import sys
import threading
from PyQt5.QtWidgets import *
from PyQt5.QtGui import *
from PyQt5.QtCore import *

# 帮我们直接运行此文件时，可以加载到上级目录的ui包
# 注意，需要放在导入ui包的前面
sys.path.append("../")

from ui.Ui_bluetooth_assist_widget import Ui_BleAssistWidget
from drivers.driver_bluetooth import *
from common.utils import *

class BleAssistWidget(QWidget):
    # 信号定义
    devices_signal = pyqtSignal(list)
    recv_data_signal = pyqtSignal(bytes)
    conn_flag_signal = pyqtSignal()
    
    def __init__(self, parent=None):
        super().__init__(parent)
        # 实例化ui模块对象，调用setupUi()方法
        self.ui = Ui_BleAssistWidget()
        self.ui.setupUi(self)
        
        # 设置窗口大小
        self.resize(900, 600)
        
        # 实例属性
        self.devices = [] # 设备列表
        self.bdt: BluetoothDataTransfer = None
        
        # 初始化UI界面
        self.init_ui()
        
        
    def refresh_devices(self):
        print("刷新设备列表")
        print("=========================================开始扫描")
        devices = BluetoothDataTransfer.scan_devices()
        # for device in devices:
        #     print(device)
        # print(devices)
        # print([device[1] for device in devices])
        # 信号发射
        self.devices_signal.emit(devices)
        print("=========================================结束扫描")

    def btn_refresh_slot(self):
        print("刷新设备按钮槽函数")
        self.update_state(1) # 1 扫描中
        # 创建线程，设置为守护线程
        t = threading.Thread(target=self.refresh_devices, daemon=True)
        t.start()
    
    def devices_slot(self, devices):
        print("设备列表槽函数")
        self.devices = devices
        self.ui.cb_devices.clear()
        for device in devices:
            self.ui.cb_devices.addItem(device[1])
            
        # 展开下拉框
        self.ui.cb_devices.showPopup()
        
        self.update_state(2) # 2 扫描完成
    
    def connect_device(self, device):
        print("连接设备线程处理函数")
        addr, name = device
        self.bdt = BluetoothDataTransfer(addr, name, 1)  # 替换为目标设备的蓝牙地址和端口号
        if not self.bdt.connect():
            print("连接失败")
            # 弹出警告框
            QMessageBox.warning(self, "警告", "连接失败")
            return
        
        print("连接成功")
        # 信号发射
        self.conn_flag_signal.emit()
        try:
            print("开始接收数据")
            while True:
                bytes_arr = self.bdt.receive_data()
                if bytes_arr:
                    # 信号发射
                    self.recv_data_signal.emit(bytes_arr)
                    # msg = decode_data(bytes_arr)
                    # print(msg)
                else:
                    # 当主动调用disconnect或设备被动断开时
                    # bytes_arr会收到长度为零bytes
                    break
        except Exception as e:
            print(e)

    def btn_connect_slot(self):
        print("连接按钮槽函数") 
        if self.bdt is not None:
            print("断开连接")
            self.bdt.disconnect() # 断开连接
            self.bdt = None
            self.update_state(3) # 3 断开连接
            return

        # 读取cb_devices中选中的设备
        device_index = self.ui.cb_devices.currentIndex()
        if device_index == -1:
            print("未选择任何设备，请重新选择")
            # 弹出警告框
            QMessageBox.warning(self, "警告", "未选择任何设备，请重新选择")
            return
        device = self.devices[device_index]
        print("连接设备:", device)
        
        
        # 启动子线程，设置为守护线程
        t = threading.Thread(target=self.connect_device, args=(device,), daemon=True)
        t.start()

    def recv_data_slot(self, bytes_arr):
        print("接收到数据")
        msg = decode_data(bytes_arr)
        print(msg)
        # 显示到ui上
        self.ui.edit_recv.append(msg)
        
    def btn_send_slot(self):
        print("发送按钮槽函数")
        # 如果蓝牙设备没有连接，对话框提示请连接蓝牙设备
        if not self.bdt:
            QMessageBox.warning(self, "警告", "请先连接蓝牙设备")
            return
        # 获取输入框的内容
        msg = self.ui.edit_send.toPlainText()
        # 如果没有输入内容，对话框提示请输入要发送的内容
        if not msg:
            QMessageBox.warning(self, "警告", "请输入要发送的内容")
            return
        
        self.bdt.send_data(msg.encode("GBK"))
        
    def conn_flag_slot(self):
        print("连接成功信号槽函数")
        self.update_state(4) # 4 连接成功
        
        
    def update_state(self, flag):
        """
        flag: 1 扫描中, 2 扫描完成 3 断开连接 4 连接成功
        """
        if flag == 1:
            # - 已经点击了，按钮禁用
            self.ui.btn_refresh.setEnabled(False)
            # - 连接设备按钮上，文字显示"扫描中……"
            self.ui.btn_connect.setText("扫描中……")
        elif flag == 2:
            # - 连接设备按钮上，文字显示"连接设备"
            self.ui.btn_connect.setText("连接设备")
        elif flag == 3:
            # - 按钮文字变为"连接设备"
            self.ui.btn_connect.setText("连接设备")
            # - 状态图片变为断开连接的图片
            self.ui.label_connect_status.setPixmap(QPixmap(":/icon/disc"))
            # - 已经连接设备的容器隐藏
            self.ui.gb_connected.hide()
            # - 扫描按钮使能可用
            self.ui.btn_refresh.setEnabled(True)
        elif flag == 4:
            # - 按钮文字变为"断开连接（已连接）"
            self.ui.btn_connect.setText("断开连接（已连接）")
            # - 状态图片变为连接成功的图片
            self.ui.label_connect_status.setPixmap(QPixmap(":/icon/connect"))
            # - 已经连接设备的容器显示
            self.ui.gb_connected.show()
            # - 扫描按钮禁用
            self.ui.btn_refresh.setEnabled(False)
            
        if self.bdt is not None:
            # self.bdt.target_address
            # self.bdt.target_name
            self.ui.label_device_name.setText(f"名称：{self.bdt.target_name}")
            self.ui.label_device_addr.setText(f"地址：{self.bdt.target_address}")


    def init_ui(self):
        # - 已经连接设备的容器隐藏
        self.ui.gb_connected.hide()
        
        # 按钮信号和槽函数绑定
        self.ui.btn_refresh.clicked.connect(self.btn_refresh_slot) # 刷新按钮
        self.ui.btn_connect.clicked.connect(self.btn_connect_slot)  # 连接按钮
        self.ui.btn_send.clicked.connect(self.btn_send_slot)   # 发送按钮
        # 清空按钮
        self.ui.btn_recv_clear.clicked.connect(self.ui.edit_recv.clear)
        self.ui.btn_send_clear.clicked.connect(self.ui.edit_send.clear)
        
        # 自定义信号绑定
        self.devices_signal.connect(self.devices_slot)
        self.recv_data_signal.connect(self.recv_data_slot)
        self.conn_flag_signal.connect(self.conn_flag_slot)

        
if __name__ == "__main__":
    app = QApplication(sys.argv)

    w = BleAssistWidget()
    w.show()

    sys.exit(app.exec_())
